package cn.com.joycode.nimble.starter.examples;

import cn.com.joycode.nimble.core.utils.ObjectMapperUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@RestController
@RequestMapping("/es")
public class TestController {

    @Autowired
    private NewsRepository newsRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @GetMapping("/add")
    public String add() {
        News n = new News();
        n.setId(RandomUtil.randomNumbers(6));
        n.setAuthor("Max Woods");
        n.setName("test");
        newsRepository.save(n);
        return "OK";
    }

    @GetMapping("/find")
    public String find() {

        return "none";
    }

    @GetMapping("/high")
    public String high() {
        String keyword = "te";
        // 构建查询
        NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
        searchQuery.withIndices("news");
        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .should(QueryBuilders.multiMatchQuery(keyword, "name").boost(5))
                .should(QueryBuilders.multiMatchQuery(keyword, "author").boost(5));
        searchQuery.withQuery(queryBuilder);
        List<String> highlightFields = new ArrayList<String>();
        highlightFields.add("name");
        highlightFields.add("author");
        HighlightBuilder.Field[] fields = new HighlightBuilder.Field[highlightFields.size()];
        for (int x = 0; x < highlightFields.size(); x++) {
            fields[x] = new HighlightBuilder.Field(highlightFields.get(x)).preTags("<span>")
                    .postTags("<span>");
        }
        searchQuery.withHighlightFields(fields);
        searchQuery.withPageable(PageRequest.of(0, 10));
        // 高亮字段
        AggregatedPage<News> page = elasticsearchTemplate.queryForPage(searchQuery.build(), News.class, new SearchResultMapper() {

            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                log.info("result");
                List<T> chunk = new ArrayList();
                searchResponse.getHits().forEach(
                        searchHit ->
                        {
                            Map<String, Object> smap = searchHit.getSourceAsMap();
                            Map<String, HighlightField> hmap = searchHit.getHighlightFields();
                            News news = new News();
                            ObjectMapperUtil.convertValue(smap, News.class);
                            chunk.add((T) news);
                        }
                );
                AggregatedPage<T> result = new AggregatedPageImpl<T>(chunk, pageable, searchResponse.getHits().getTotalHits());

                return result;
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                log.info("hint");
                return null;
            }
        });

        return Long.toString(page.getTotalElements());
    }

}